/*
*  Copyright 2019-2020 Zheng Jie
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package me.zhengjie.modules.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.excel.EasyExcel;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.system.domain.*;
import me.zhengjie.modules.system.excel.vo.GodownEntryDetailVo;
import me.zhengjie.modules.system.repository.GodownEntryDetailRepository;
import me.zhengjie.modules.system.repository.PurchaseDataRepository;
import me.zhengjie.modules.system.repository.PurchaseRequestDetailRepository;
import me.zhengjie.modules.system.service.dto.PurchaseDataDto;
import me.zhengjie.modules.system.service.dto.PurchaseDataQueryCriteria;
import me.zhengjie.modules.system.service.mapstruct.PurchaseDataMapper;
import me.zhengjie.utils.*;
import lombok.RequiredArgsConstructor;
import me.zhengjie.modules.system.repository.GodownEntryRepository;
import me.zhengjie.modules.system.service.GodownEntryService;
import me.zhengjie.modules.system.service.dto.GodownEntryDto;
import me.zhengjie.modules.system.service.dto.GodownEntryQueryCriteria;
import me.zhengjie.modules.system.service.mapstruct.GodownEntryMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.*;
import java.io.IOException;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.multipart.MultipartFile;

/**
* @website https://eladmin.vip
* @description 服务实现
* @author 李忠臻
* @date 2024-02-24
**/
@Service
@RequiredArgsConstructor
public class GodownEntryServiceImpl implements GodownEntryService {

    private final PurchaseDataRepository purchaseDataRepository;
    private final GodownEntryDetailRepository godownEntryDetailRepository;
    private final GodownEntryRepository godownEntryRepository;
    private final GodownEntryMapper godownEntryMapper;
    private final PurchaseDataMapper purchaseDataMapper;

    @Override
    public PageResult<GodownEntryDto> queryAll(GodownEntryQueryCriteria criteria, Pageable pageable){
        Page<GodownEntry> page = godownEntryRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
        return PageUtil.toPage(page.map(godownEntryMapper::toDto));
    }

    @Override
    public List<GodownEntryDto> queryAll(GodownEntryQueryCriteria criteria){
        return godownEntryMapper.toDto(godownEntryRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
    }

    @Override
    @Transactional
    public GodownEntryDto findById(Long id) {
        GodownEntry godownEntry = godownEntryRepository.findById(id).orElseGet(GodownEntry::new);
        ValidationUtil.isNull(godownEntry.getId(),"GodownEntry","id",id);
        return godownEntryMapper.toDto(godownEntry);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(GodownEntry resources) {
        godownEntryRepository.save(resources);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(GodownEntry resources) {
        GodownEntry godownEntry = godownEntryRepository.findById(resources.getId()).orElseGet(GodownEntry::new);
        ValidationUtil.isNull( godownEntry.getId(),"GodownEntry","id",resources.getId());
        godownEntry.copy(resources);
        godownEntryRepository.save(godownEntry);
    }

    @Transactional
    @Override
    public void deleteAll(Long[] ids) {
        List<GodownEntry> godownEntryList = godownEntryRepository.findAllById(Arrays.asList(ids));
        if (godownEntryList.stream().filter(g->g.getStatus() == 1).findAny().isPresent()) {
            throw new BadRequestException("删除的入库清单状态为已审核，不能删除！请重新选择");
        }
        godownEntryRepository.deleteAllById(Arrays.asList(ids));
    }

    @Override
    public void download(List<GodownEntryDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (GodownEntryDto godownEntry : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("文件名", godownEntry.getFilename());
            map.put("状态（0：未审核,1：已审核 2：已取消）", godownEntry.getStatus());
            map.put("审批人", godownEntry.getAuditBy());
            map.put("审批时间", godownEntry.getAuditTime());
            map.put("创建者", godownEntry.getCreateBy());
            map.put("更新者", godownEntry.getUpdateBy());
            map.put("创建日期", godownEntry.getCreateTime());
            map.put("更新时间", godownEntry.getUpdateTime());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Transactional
    @Override
    public void pass(Long id) {
        GodownEntry godownEntry = godownEntryRepository.findById(id).orElseGet(GodownEntry::new);
        ValidationUtil.isNull( godownEntry.getId(),"GodownEntry","id", id);
        godownEntry.setStatus(1);
        godownEntry.setAuditBy(SecurityUtils.getCurrentUser().getUsername());
        godownEntry.setAuditTime(new Timestamp(System.currentTimeMillis()));
        godownEntryRepository.save(godownEntry);
        List<GodownEntryDetail> godownEntryDetailList = godownEntryDetailRepository.findByGodownEntryId(id);
        godownEntryDetailList = godownEntryDetailList.stream().filter(g -> g.getPurchaseDataId() != null).collect(Collectors.toList());
        for (GodownEntryDetail godownEntryDetail : godownEntryDetailList) {
            PurchaseData purchaseData = purchaseDataRepository.getById(godownEntryDetail.getPurchaseDataId());
            if ("大货".equals(purchaseData.getPurchaseAttribute())) {
                purchaseData.setGodownQuantity(new BigDecimal(purchaseData.getGodownQuantity()).add(new BigDecimal(godownEntryDetail.getQuantity())).intValue());
                purchaseData.setOnPassageQuantity(new BigDecimal(purchaseData.getQuantity()).subtract(new BigDecimal(purchaseData.getGodownQuantity())).intValue());
            }
//            purchaseData.setGodownEntryDate(godownEntryDetail.getGodownEntryDate());
//            purchaseData.setTaxAmount(godownEntryDetail.getTaxAmount());
//            purchaseData.setUntaxAmount(godownEntryDetail.getUntaxAmount());
            purchaseDataRepository.save(purchaseData);
        }
    }

    @Override
    public void cancel(Long id) {
        GodownEntry godownEntry = godownEntryRepository.findById(id).orElseGet(GodownEntry::new);
        ValidationUtil.isNull( godownEntry.getId(),"GodownEntry","id", id);
        godownEntry.setStatus(2);
        godownEntry.setAuditBy(SecurityUtils.getCurrentUser().getUsername());
        godownEntry.setAuditTime(new Timestamp(System.currentTimeMillis()));
        godownEntryRepository.save(godownEntry);
    }

    /**
     * 入库单上传后需要查询相关b2b号和型号的入库数据，如果对应的采购性质是直发，那么相对应的入库单可以直接配上这条数据
     * @param name
     * @param file
     */
    @Transactional
    @Override
    public void upload(String name, MultipartFile file) {
        //校验采购单文件名是否重复
        List<GodownEntry> purchaseRequestList = godownEntryRepository.findByFilename(file.getOriginalFilename());
        if (CollectionUtil.isNotEmpty(purchaseRequestList)) {
            throw new BadRequestException("上传的附件文件名称已经存在，请核实后重新上传");
        }
        try {
            List<GodownEntryDetailVo> l = EasyExcel.read(file.getInputStream(), GodownEntryDetailVo.class, null).sheet().doReadSync();
            l = l.stream().sorted(Comparator.comparing(GodownEntryDetailVo::getQuantity).reversed()).collect(Collectors.toList());
//            GodownEntryDetailVo firstGodownEntryDetailVo = l.get(0);
            GodownEntry godownEntry = new GodownEntry();
            godownEntry.setStatus(0);
            godownEntry.setFilename(file.getOriginalFilename());
            godownEntryRepository.save(godownEntry);

            Set<String> b2bList = l.stream().map(GodownEntryDetailVo::getCustomerOrderNo).collect(Collectors.toSet());
            List<PurchaseDataDto> purchaseDataDtoTempList = purchaseDataMapper.toDto(purchaseDataRepository.findByB2bIn(b2bList));

            for (GodownEntryDetailVo godownEntryDetailVo : l) {
                //获取能匹配的数据
                List<PurchaseDataDto> purchaseDataList = purchaseDataDtoTempList.stream().
                        filter(d -> d.getModel().equals(godownEntryDetailVo.getModel()) && d.getB2b().equals(godownEntryDetailVo.getCustomerOrderNo())).
                        collect(Collectors.toList());
//                        findByB2bAndModelOrderByIndex(godownEntryDetailVo.getCustomerOrderNo(), godownEntryDetailVo.getModel());
                if (CollectionUtil.isEmpty(purchaseDataList)) {
                    throw new BadRequestException("b2b:" + godownEntryDetailVo.getCustomerOrderNo() + " 型号：" +
                            godownEntryDetailVo.getModel() + "没有找到对应的采购数据，请核实后重新导入");
                }

                if ("直发".equals(purchaseDataList.get(0).getPurchaseAttribute())) {
                    GodownEntryDetail godownEntryDetail = new GodownEntryDetail();
                    BeanUtils.copyProperties(godownEntryDetailVo, godownEntryDetail);
                    godownEntryDetail.setGodownEntryId(godownEntry.getId());
                    godownEntryDetail.setGodownEntryDate(new Timestamp(godownEntryDetailVo.getGodownEntryDate().getTime()));
                    godownEntryDetail.setPurchaseDataId(purchaseDataList.get(0).getId());
                    godownEntryDetail.setSupplierName(purchaseDataList.get(0).getSupplierName());
                    godownEntryDetail.setInitBy(purchaseDataList.get(0).getInitBy());
                    godownEntryDetailRepository.save(godownEntryDetail);
                } else {
                    //获取单条入库的数量
                    BigDecimal quantity = BigDecimal.valueOf(godownEntryDetailVo.getQuantity());
                    purchaseDataList = purchaseDataList.stream().filter(d -> d.getOnPassageQuantity() > 0).
                            sorted(Comparator.comparing(PurchaseDataDto::getOnPassageQuantity).reversed()).collect(Collectors.toList());
                    for (PurchaseDataDto purchaseData : purchaseDataList) {
                        GodownEntryDetail godownEntryDetail = new GodownEntryDetail();
                        BeanUtils.copyProperties(godownEntryDetailVo, godownEntryDetail);
                        godownEntryDetail.setGodownEntryId(godownEntry.getId());
                        godownEntryDetail.setGodownEntryDate(new Timestamp(godownEntryDetailVo.getGodownEntryDate().getTime()));
                        godownEntryDetail.setPurchaseDataId(purchaseData.getId());
                        godownEntryDetail.setSupplierName(purchaseData.getSupplierName());
                        godownEntryDetail.setInitBy(purchaseData.getInitBy());
                        if (quantity.compareTo(BigDecimal.valueOf(purchaseData.getOnPassageQuantity())) >= 0) {
                            godownEntryDetail.setQuantity(purchaseData.getOnPassageQuantity());
                            quantity = quantity.subtract(BigDecimal.valueOf(purchaseData.getOnPassageQuantity()));
                            purchaseData.setOnPassageQuantity(0);

                        } else {
                            godownEntryDetail.setQuantity(quantity.intValue());
                            quantity = BigDecimal.ZERO;
                            purchaseData.setOnPassageQuantity(BigDecimal.valueOf(purchaseData.getOnPassageQuantity()).subtract(quantity).intValue());

                        }
                        //同步缓存中的数据
                        purchaseDataDtoTempList.stream().filter(t -> t.getId() == purchaseData.getId()).findFirst().get()
                                .setOnPassageQuantity(purchaseData.getOnPassageQuantity());
//                        godownEntryDetail.setUntaxAmount(godownEntryDetail.getTaxAmount().divide(godownEntryDetail.getUnitPrice()));
                        godownEntryDetail.setTaxAmount(new BigDecimal(godownEntryDetail.getQuantity()).multiply(godownEntryDetail.getUnitPrice()));
                        godownEntryDetailRepository.save(godownEntryDetail);
                        if (quantity.compareTo(BigDecimal.ZERO) <= 0) {
                            break;
                        }
                    }
                    if (quantity.compareTo(BigDecimal.ZERO) > 0) {
                        throw new BadRequestException("b2b:" + godownEntryDetailVo.getCustomerOrderNo() + " 型号：" +
                                godownEntryDetailVo.getModel() + "导入的入库数量多于采购数据，请核实后重新导入");
                    }
                }

            }

        } catch (IOException e) {
            e.printStackTrace();
            throw new BadRequestException(e.getMessage());
        }
    }

}